/**
 * Forwarding Refs
 * React.forwardRef 在16.3新增，用于转发 ref
 * 函数组件在16.8.4之后支持 ref
 */
import React, {
  FC,
  useCallback,
  useRef,
  useImperativeHandle,
  useState,
} from 'react';
import { Button, Modal } from 'antd';

/**
 * 暴露的方法, 适用`{ComponentName}Methods`形式命名
 */
export interface MyModalMethods {
  show(): void;

  hide(): void;
}

export interface MyModalProps {
  title?: React.ReactNode;
  onOk?: () => void;
  onCancel?: () => void;
}

/**
 * React.formardRef((props, ref)=>{}) 将父组件的 ref 透传过来，即：实现 ref 的转发
 * props: 父组件传递的props
 * ref: 父组件传递的ref
 * 一句话：通过React.forwardRef 转发ref，让父组件可以使用子组件 useImperativeHandle 之后暴露出来的实例，然后直接控制子组件或者子组件元素的行为
 */
const MyModal = React.forwardRef<MyModalMethods, MyModalProps>((props, ref) => {
  const [visible, setVisible] = useState();

  /**
   * useImperativeHandle(ref, createHandle, [deps]) 自定义的暴露给父组件的实例
   * [deps]: 依赖列表，当监听的依赖发生变化时，重新将子组件的实例属性输出到父组件
   */
  useImperativeHandle(ref, () => ({
    show: () => setVisible(true),
    hide: () => setVisible(false),
  }));

  return (
    <Modal visible={visible} {...props}>
      我被父组件控制了
    </Modal>
  );
});

const Demo4: FC<{}> = () => {
  //引用
  const modal = useRef<MyModalMethods | null>(null);

  const confirm = useCallback(() => {
    if (modal.current) {
      //使用暴露的方法控制子组件
      modal.current.show();
    }
  }, []);

  const handleOk = useCallback(() => {
    if (modal.current) {
      modal.current.hide();
    }
  }, []);

  return (
    <div>
      <Button onClick={confirm} type="primary">
        打开弹框
      </Button>
      <MyModal ref={modal} title="确认框" onOk={handleOk} onCancel={handleOk} />
    </div>
  );
};

export default Demo4;
